/*
 * MISC Novell eDirectory evtFilteredMonitorEventsRequest Function
 * 	Heap Overflow Attempt
 * 
 * Copyright (C) 2007 Sourcefire, Inc. All Rights Reserved
 * 
 * Writen by Patrick Mullen <pmullen@sourcefire.com>
 *
 * This file may contain proprietary rules that were created, tested and
 * certified by Sourcefire, Inc. (the "VRT Certified Rules") as well as
 * rules that were created by Sourcefire and other third parties and
 * distributed under the GNU General Public License (the "GPL Rules").  The
 * VRT Certified Rules contained in this file are the property of
 * Sourcefire, Inc. Copyright 2005 Sourcefire, Inc. All Rights Reserved.
 * The GPL Rules created by Sourcefire, Inc. are the property of
 * Sourcefire, Inc. Copyright 2002-2005 Sourcefire, Inc. All Rights
 * Reserved.  All other GPL Rules are owned and copyrighted by their
 * respective owners (please see www.snort.org/contributors for a list of
 * owners and their respective copyrights).  In order to determine what
 * rules are VRT Certified Rules or GPL Rules, please refer to the VRT
 * Certified Rules License Agreement.
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"
#include "so-util_ber.h"

/* declare detection functions */
int ruleNOVELL_EVENTSREQUESTeval(void *p);

static RuleReference ruleNOVELL_EVENTSREQUESTref0 = 
{
    "url", /* type */
    "labs.idefense.com/intelligence/vulnerabilities/display.php?id=427" /* value */
};
static RuleReference ruleNOVELL_EVENTSREQUESTref1 =
{
    "cve", /* type */
    "2006-4509"
};
static RuleReference ruleNOVELL_EVENTSREQUESTref2 =
{
    "bugtraq", /* type */
    "20663"
};

static RuleReference *ruleNOVELL_EVENTSREQUESTrefs[] =
{
    &ruleNOVELL_EVENTSREQUESTref0,
    &ruleNOVELL_EVENTSREQUESTref1,
    &ruleNOVELL_EVENTSREQUESTref2,
    NULL
};

static FlowFlags ruleNOVELL_EVENTSREQUESTflow =
{
    FLOW_ESTABLISHED|FLOW_TO_SERVER
};

static RuleOption ruleNOVELL_EVENTSREQUESToption0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &ruleNOVELL_EVENTSREQUESTflow
    }
};

static ContentInfo ruleNOVELL_EVENTSREQUESTcontent0 =
{
    (uint8_t *)"|30|",     /* pattern to search for */
    1,                      /* depth */
    0,                      /* offset */
    CONTENT_BUF_NORMALIZED,                      /* flags */
    NULL,                   /* holder for boyer/moore info */
    NULL,                   /* holder for byte representation of "NetBus" */
    0,                      /* holder for length of byte representation */
    0                       /* holder of increment length */
};

static RuleOption ruleNOVELL_EVENTSREQUESToption1 =
{
    OPTION_TYPE_CONTENT,
    {
        &ruleNOVELL_EVENTSREQUESTcontent0
    }
};

static ContentInfo ruleNOVELL_EVENTSREQUESTcontent1 =
{
    (uint8_t *)"2.16.840.1.113719.1.27.100.",  /* pattern to search for */
    0,                      /* depth */
    0,                      /* offset */
    CONTENT_BUF_NORMALIZED,                      /* flags */
    NULL,                   /* holder for boyer/moore info */
    NULL,                   /* holder for byte representation of "NetBus" */
    0,                      /* holder for length of byte representation */
    0                       /* holder of increment length */
};

static RuleOption ruleNOVELL_EVENTSREQUESToption2 =
{
    OPTION_TYPE_CONTENT,
    {
        &ruleNOVELL_EVENTSREQUESTcontent1
    }
};


static PCREInfo ruleNOVELL_EVENTSREQUESTpcre0 =
{
    "2.16.840.1.113719.1.27.100.(84|79)", /* pattern (now in snort content format) */
    0, /* compiled expression */
    0, /* compiled extra */
    0, /* compile flags */
    CONTENT_BUF_NORMALIZED /* flags */ // XXX - need to add CONTENT_FAST_PATTERN support
};

static RuleOption ruleNOVELL_EVENTSREQUESToption3 =
{
    OPTION_TYPE_PCRE,
    {
        &ruleNOVELL_EVENTSREQUESTpcre0
    }
};


RuleOption *ruleNOVELL_EVENTSREQUESToptions[] =
{
    &ruleNOVELL_EVENTSREQUESToption0,
    &ruleNOVELL_EVENTSREQUESToption1,
    &ruleNOVELL_EVENTSREQUESToption2,
    &ruleNOVELL_EVENTSREQUESToption3,
    NULL
};

static RuleMetaData ruleNOVELL_EVENTSREQUESTservice1 =
{
    "service ldap"
};

static RuleMetaData ruleNOVELL_EVENTSREQUESTpolicy1 =
{
    "policy max-detect-ips drop"
};

static RuleMetaData *ruleNOVELL_EVENTSREQUESTmetadata[] =
{
    &ruleNOVELL_EVENTSREQUESTservice1,
    &ruleNOVELL_EVENTSREQUESTpolicy1,
    NULL
};

Rule ruleNOVELL_EVENTSREQUEST = {
   /* rule header */
   {
       IPPROTO_TCP, /* proto */
       "any", /* SRCIP     */
       "any", /* SRCPORT   */
       0, /* DIRECTION */
       HOME_NET, /* DSTIP     */
       "389", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid (HARDCODED!!!) */
       13510, /* sigid */
       5, /* revision  */
       "attempted-admin", /* classification, generic */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "SERVER-OTHER Novell eDirectory EventsRequest heap overflow attempt",     /* message */
       ruleNOVELL_EVENTSREQUESTrefs /* ptr to references */
       ,ruleNOVELL_EVENTSREQUESTmetadata
   },
   ruleNOVELL_EVENTSREQUESToptions, /* ptr to rule options */
   &ruleNOVELL_EVENTSREQUESTeval, /* ptr to rule detection function */
   0, /* am I initialized yet? */
   0, /* number of options */
   0  /* don't alert */
};


/* detection functions */

int ruleNOVELL_EVENTSREQUESTeval(void *p) {
   int retval;

   const uint8_t *cursor_normal; /*, *end_of_payload; */

   SFSnortPacket *sp = (SFSnortPacket *) p;

   BER_ELEMENT element;

   if(sp == NULL)
      return RULE_NOMATCH;

   if(sp->payload == NULL)
      return RULE_NOMATCH;

   /* call flow match */
   if(checkFlow(sp, ruleNOVELL_EVENTSREQUESToptions[0]->option_u.flowFlags) <= 0 )
      return RULE_NOMATCH;

   /* call content match "|30|" */
   if(contentMatch(sp, ruleNOVELL_EVENTSREQUESToptions[1]->option_u.content, &cursor_normal) <= 0) {
      return RULE_NOMATCH;
   }

   /* The fast pattern matcher already assures us that the content match option containing the OID
      exists.  We're going to skip checking that content and go right for the PCRE to save time */

   if(pcreMatch(sp, ruleNOVELL_EVENTSREQUESToptions[3]->option_u.pcre, &cursor_normal) <= 0) {
      return RULE_NOMATCH;
   }

   /* So at this point, we know the first byte is "|30|" (the universal sequence), we know
      we have an OID, and the cursor is pointing to the byte following the OID.  We are going to
      make the reasonable assumption that if the anchors following this point all match up, the
      portion between the universal sequence and the OID contains the LDAP version and the
      extendedRequest sequence start (0x77 followed by a length field).
   */

   /* requestValue sequence start */
   retval = ber_get_element(p, cursor_normal, &element);

   if(retval < 0 || element.type != 0x81)
      return(RULE_NOMATCH);

   cursor_normal = element.data.data_ptr;

   /* sequence start */
   retval = ber_get_element(p, cursor_normal, &element);

   if(retval < 0 || element.type != 0x30)
      return RULE_NOMATCH;

   cursor_normal = element.data.data_ptr;

   /* eventCount */
   retval = ber_get_element(p, cursor_normal, &element);

   /* Because we're going to extract the int, we need to make sure
      the full data is present
   */
   if((retval < 0) || (element.type != 0x02) || (retval != element.data_len))
      return RULE_NOMATCH;

   /* get value of eventCount */
   retval = ber_extract_int_val(&element);

   if(retval < 0) 
      return RULE_NOMATCH;

   /* Malicious request if eventCount > 0x10000000 */
   if(element.data.int_val > 0x10000000)
      return RULE_MATCH;

   return RULE_NOMATCH; 
}

/*
Rule *rules[] = {
    &ruleNOVELL_EVENTSREQUEST,
    NULL
};

*/
